/*
 * vim: ts=4 sw=4 fdm=marker noet tw=78 ai
 * %%LICENSE%%
 */
#include <sys/cdefs.h>
#ifdef __FBSDID
__FBSDID("$Coar$");
#endif
#include <sys/queue.h>

#include <assert.h>
#include <stdlib.h>
#include <string.h>

#include <err.h>

#include <ldap.h>
#include <ldap_schema.h>

#include "extern.h"
#include "search.h"
#include "classes.h"

#define UNIMPLEMENTED LDAP_SUCCESS

static const int relaxed = LDAP_SCHEMA_ALLOW_ALL;
static const int hyper   = LDAP_SCHEMA_ALLOW_NONE;

static class_entry_t * class_entry_new(LDAPObjectClass *);

int
lde_add_class(runtime_t *ctx, char *schema)
{
	LDAPObjectClass *oc;
	const char *errpos;
	class_entry_t *new, *tmp;
	int retval = LDAP_SUCCESS;

	assert(ctx != NULL);
	assert(ctx->ld != NULL);
	assert(schema != NULL);
	TRACEIN(ctx, __func__, "schemalen = %zu", strlen(schema));

	if( ctx->ocl == NULL )
	{
		if( (ctx->ocl = malloc(sizeof(class_list_t))) == NULL )
		{
			retval = LDAP_OPERATIONS_ERROR;
			goto out;
		}
		SLIST_INIT(LDE_LIST_HEAD(ctx->ocl));
		ctx->ocl->cnt = 0;
	}

	oc = ldap_str2objectclass(schema, &retval, &errpos, relaxed);
	if( retval != 0 )
	{
		warnx("%s", ldap_scherr2str(retval));
		warnx("At %20s", errpos);
		retval = LDAP_OPERATIONS_ERROR;
	}
	else
	{
		int found = 0;
		new = class_entry_new(oc);
		SLIST_FOREACH(tmp, LDE_LIST_HEAD(ctx->ocl), next)
		{
			if( strcmp(tmp->name, new->name) == 0 )
			{
				found++;
				break;
			}
		}
		if( ! found )
		{
			LOG(ctx, 2, "Adding Objectlass: %s", new->name);
			SLIST_INSERT_HEAD(LDE_LIST_HEAD(ctx->ocl), new, next);
			ctx->ocl->cnt++;
		}
	}

out:
	TRACEOUT(ctx, __func__, "Returning 0x%02x", retval);

	return(retval);
}

static class_entry_t *
class_entry_new(LDAPObjectClass *oc)
{
	class_entry_t *retval;

	if( (retval = malloc(sizeof(class_entry_t))) == NULL )
		return NULL;

	retval->lo = oc;
	if( oc->oc_names[0] == NULL )
	{
		warnx("No name known for object class. Using OID");
		retval->name = strdup(oc->oc_oid);
	}
	else
		retval->name = strdup(oc->oc_names[0]);

	return (retval);
}
